home *** CD-ROM | disk | FTP | other *** search
- Path: solon.com!not-for-mail
- From: kjm@sbphy.physics.ucsb.edu ( Kevin Miller)
- Newsgroups: comp.lang.c,comp.lang.c.moderated
- Subject: Re: 8 Queens prog help
- Date: 20 Apr 1996 13:34:23 -0500
- Organization: University of California, Santa Barbara
- Sender: clc@solutions.solon.com
- Approved: clc@solutions.solon.com
- Message-ID: <4lbanf$ljv@solutions.solon.com>
- References: <4l87ud$73u@solutions.solon.com>
- NNTP-Posting-Host: solutions.solon.com
-
- Mike Mitchell <72724.2067@CompuServe.COM> writes:
-
- >Need some C help this week. I'm currently working on a program
- >called "Eight Queens". Basically, I have to place 8 queen chess
- >pieces on an 8x8 chess board without them checking one another.
-
- >The instructer wants us to use a "backtracking algorithm" (i.e. a
- >tree structure) to accomplish this. My thoughts thus far are to
- >place my first queen randomly and mark that space with a 'Q'
- >character and then mark off all the squares in its legal paths
- >(all adjacent squares vertical, horizontal, and diagonal to the
- >ends of the board) with an 'X' character. Board is initialized
- >to Nulls.
-
- >When the next queen piece is placed I will check to see if
- >another queen is in one of its paths. If there isn't I will
- >place the piece and mark off its paths otherwise I will return
- >the square to NULL and move to the next NULL square.
-
- >Am I approaching this the right way or should I be handling this
- >another way? Can someone explain how a tree structure
- >accomplishes this?
-
- >We did a similar problem in class using the knight piece and its
- >legal moves. Well, needless to say the number of legal moves a
- >queen can make, make this problem a little more difficult.
-
- If anything, the greater number of moves that the queen can make should
- make this problem *easier* to do than the corresponding problem for the
- knight. This is assuming, of course, that your algorithm for solving
- the knight problem was actually exhaustive. The number of ways of
- placing eight knights on a chessboard without any of them attacking
- each other is large enough that a non-exhaustive algorithm, by which
- I mean one that overlooks some possible solutions, would still have
- a good chance of finding at least one solution. (Hell, putting eight
- knights all on the same row would work.) But an algorithm that would
- correctly find *all* solutions to the "eight knights" problem should
- be quite easy to modify for the "eight queens" problem.
-
- I am not sure why your instructor wants you to use a tree, if that is
- really what he meant. Storing the whole search tree would use up an
- awfully wasteful amount of memory, and serve no purpose. Possibly he
- means that you should have stored, at any one time, one path along
- the search tree. (But that would not really need to be stored in
- a tree-like structure; it would just be a simple array.)
-
- What I would do is first invent a way of numbering the squares with a
- single integer. For example, let H be the horizontal coordinate and
- let V be the vertical coordinate, where both H and V take values
- between 0 and 7 inclusive, and let the number associated with a square
- be N = 8 * V + H. The squares then have numbers ranging from 0 to 63.
-
- Then I would create an array of dimension 8 that would hold the positions
- of each of the eight queens. Initialize this array to all zeros.
- This is not a legal position, in that it has all of the queens on top
- of each other in the lower left-hand corner. But this is OK, this is
- the starting point, not the solution.
-
- Then you need to start iterating, going from one possible solution to
- another, until you get to (or go past) the last possible solution, where
- all eight queens are on square 63.
-
- Now how do you go from one possible solution to another, in a
- way that will generate all of the solutions and yet be efficient?
- One (inefficient) way is what I would call the odometer method.
- You increment the last element in the array. If that causes it to
- exceed 63, then you set it to zero and increment the element just
- before it. If incrementing *that* element causes *it* to exceed
- 63, then set that element to zero also and then increment the element
- preceding that one. Repeat this in an obvious way until you get
- an element that does not exceed 63 after it is incremented. The
- result is the next possible solution for you to examine. You must
- then check to see if it meets all of the requirements. If so, print
- it out. If not, go on to the next possible solution.
-
- The odometer method will probably not give you an answer in the time
- that you will have available on your computer. The entire search
- would require 64-raised-to-the-8'th-power iterations, which
- is roughly 2.8e+14, in the usual floating-point notation.
-
- So here is a much more efficient way, which I think may be what your
- professor was calling a backtracking algorithm. (Someone please correct
- me if I am wrong. I am mostly self-taught, so I don't know the names
- for a lot of these things.) Suppose you have just examined the following
- configuration:
-
- (0,10,25,3,4,5,6,7)
-
- This corresponds to this board position:
-
- +-----------------+
- | . . . . . . . . |
- | . . . . . . . . |
- | . . . . . . . . |
- | . . . . . . . . |
- 25 >| . Q . . . . . . |
- | . . . . . . . . |
- 10 >| . . Q . . . . . |
- | Q . . Q Q Q Q Q |
- +-----------------+
- ^ ^ ^ ^ ^ ^
- 0 3 4 5 6 7
-
- If you follow the odometer algorithm, then you will end up trying all
- possible alternative positions for the last queen (now on square 7), and
- then you will try the next position for the queen now on square 6, and
- then try all possible positions for the last queen again. All of
- this, in spite of the fact that the position will be unacceptable no
- matter where you put the queens that are now on squares 6 and 7, simply
- because the queens on squares 0 and 3 are attacking each other.
- So what you should do is the following. Search through the array to find
- the first queen in the array whose position is unacceptable because of
- one of the queens that came earlier in the array. In this example, this
- will be the queen on square 3. Increment that array element, so the 3
- becomes a 4, and then set all of the array elements after that to 0.
- This will give you this configuration:
-
- (0,10,25,4,0,0,0,0)
-
- This is the next configuration which you must examine. It is also
- unacceptable, both because the queen on square 4 is in the same row
- with a queen on square 0, and also because there are actually five
- queens all on the same square, namely square 0. Nevertheless, you
- have skipped over millions of pointless-to-consider configurations.
- In any case, you keep repeating this process. But there is a
- complication we still haven't considered for this algorithm.
- Eventually you may arrive at a configuration like the following:
-
- (0,10,25,63,3,4,5,6)
-
- This corresponds to this board position:
-
- +-----------------+
- 63 >| . . . . . . . Q |
- | . . . . . . . . |
- | . . . . . . . . |
- | . . . . . . . . |
- 25 >| . Q . . . . . . |
- | . . . . . . . . |
- 10 >| . . Q . . . . . |
- | Q . . Q Q Q Q . |
- +-----------------+
- ^ ^ ^ ^ ^
- 0 3 4 5 6
-
- Now the queens on squares 0, 10, and 25 do not attack each other, but
- the queen on square 63 is on the same diagonal as the queen on square 0.
- This means that we should increment the 63, and set all the elements
- after it in the array equal to zero, giving us this configuration:
-
- (0,10,25,64,0,0,0,0)
-
- But 64 is not the number of any square. Square numbers only run
- from 0 to 63. So we set the 64 equal to zero, and increment the
- preceding element, giving us this configuration:
-
- (0,10,26,0,0,0,0,0)
-
- This is our next configuration to consider, and we continue as before.
- If you ever get to the point where you are forced to increment
- the first element (i.e., the element Arr[0], where Arr is the
- array name) *and* incrementing it causes *it* to exceed 64, then you
- have searched all posibilities, and you should stop. For example, you
- might encounter this configuration:
-
- (63,63,0,0,0,0,0,0)
-
- The second queen is on the same square (63) as the first one, so you
- should increment the second 63, and set everything after it to zero,
- giving you this:
-
- (63,64,0,0,0,0,0,0)
-
- But then the second element exceeds 63, so you set it equal to zero and
- increment the element before it, giving you this:
-
- (64,0,0,0,0,0,0,0)
-
- But now the very first element is 64, which exceeds 63, so you can stop.
-
- By the way, this is not really a C question. The comments above apply
- equally well, whether you are programming in C, Fortran, assembly
- language, or even (gag) Cobol.
-
- - Kevin Jay Miller
- `
-